package com.huxi.lang.object.support;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.tuple.ImmutablePair;

/**
 * 哈希构建器
 * 
 * @author jian.wu
 *
 * @param <K>
 * @param <V>
 */
public class MapBuilder<K, V> {

	private Map<K, V> map;

	public MapBuilder(Map<K, V> map) {
		this.map = map != null ? map : new LinkedHashMap<>();
	}

	public MapBuilder() {
		this(new HashMap<>());
	}

	public Map<K, V> build() {
		return map;
	}

	public Map<K, V> build(boolean immutable) {
		return immutable ? Collections.unmodifiableMap(map) : map;
	}

	public MapBuilder<K, V> addAll(Map<? extends K, ? extends V> other) {
		if (other != null) {
			for (Entry<? extends K, ? extends V> entry : other.entrySet()) {
				add(entry.getKey(), entry.getValue());
			}
		}
		return this;
	}

	public MapBuilder<K, V> addAll(Collection<Entry<? extends K, ? extends V>> other) {
		if (other != null) {
			for (Entry<? extends K, ? extends V> entry : other) {
				add(entry.getKey(), entry.getValue());
			}
		}
		return this;
	}

	public MapBuilder<K, V> addAll(Entry<K, V>[] other) {
		if (other != null) {
			for (Entry<K, V> entry : other) {
				add(entry.getKey(), entry.getValue());
			}
		}
		return this;
	}

	public MapBuilder<K, V> add(Entry<? extends K, ? extends V> entry) {
		if (entry != null) {
			add(entry.getKey(), entry.getValue());
		}
		return this;
	}

	public MapBuilder<K, V> negateAddAll(Map<? extends V, ? extends K> other) {
		if (other != null) {
			for (Entry<? extends V, ? extends K> entry : other.entrySet()) {
				negateAdd(entry);
			}
		}
		return this;
	}

	public MapBuilder<K, V> negateAddAll(Collection<Entry<? extends V, ? extends K>> other) {
		if (other != null) {
			for (Entry<? extends V, ? extends K> entry : other) {
				negateAdd(entry);
			}
		}
		return this;
	}

	public MapBuilder<K, V> negateAdd(Entry<? extends V, ? extends K> entry) {
		if (entry != null) {
			add(entry.getValue(), entry.getKey());
		}
		return this;
	}

	@SuppressWarnings("unchecked")
	public MapBuilder<K, V> entryAddAll(Object[][] other) throws RuntimeException {
		if (!(other == null || other.length == 0)) {
			Entry<K, V>[] list = new Entry[other.length];
			for (int i = 0; i < other.length; i++) {
				Object[] entry = other[i];
				K key = (K) entry[0];
				V val = (V) entry[1];
				list[i] = createImmutableEntry(key, val);
			}
			addAll(list);
		}
		return this;
	}

	@SuppressWarnings("unchecked")
	public MapBuilder<K, V> entryAddAll(List<Object[]> other) throws RuntimeException {
		if (!(other == null || other.size() == 0)) {
			ArrayList<Entry<? extends K, ? extends V>> list = new ArrayList<>(other.size());
			for (Object[] entry : other) {
				K key = (K) entry[0];
				V val = (V) entry[1];
				list.add(createImmutableEntry(key, val));
			}
			addAll(list);
		}
		return this;
	}

	@SuppressWarnings("unchecked")
	public MapBuilder<K, V> entryAdd(Object[] entry) throws RuntimeException {
		if (entry != null && entry.length == 2) {
			K key = (K) entry[0];
			V val = (V) entry[1];
			add(key, val);
		}
		return this;
	}

	/**
	 * 内部哈希增加多组键值项
	 * <p>
	 * <code>
	 * List<Object> entrys = Arrays.asList(new Object[] {"a",1,"b",2});//拉平的键值项列表<br>
	 * Map<String,Integer> m1 = new MapBuilder<>().flatAddAll(entrys).build();
	 * <br><br>//以下代码效果相等<br><br>
	 * Map<String,Integer> m2 = new MapBuilder<>().add("a",1).add("b",2).build();
	 * </code><br>
	 * 
	 * </p>
	 * 
	 * @param other 多组键值项拉平的列表
	 * @return 自身
	 * @throws RuntimeException
	 * @see {@link #flatAddAll(Object[])}
	 */
	@SuppressWarnings("unchecked")
	public MapBuilder<K, V> flatAddAll(List<? extends Object> other) throws RuntimeException {
		
		if (!(other == null || other.size() == 0)) {
			Iterator<? extends Object> itor = other.iterator();
			ArrayList<Entry<? extends K, ? extends V>> list = new ArrayList<>();
			while (itor.hasNext()) {
				K key = (K) itor.next();
				V val = (V) (itor.hasNext() ? itor.next() : null);
				list.add(createImmutableEntry(key, val));
			}
			addAll(list);
		}
		return this;
	}

	/**
	 * 内部哈希增加多组键值项
	 * <p>
	 * <code>
	 * Map<String,Integer> m1 = new MapBuilder<>().flatAddAll("a",1,"b",2).build();
	 * <br><br>//以下代码效果相等<br><br>
	 * Map<String,Integer> m2 = new MapBuilder<>().add("a",1).add("b",2).build();
	 * </code><br>
	 * 
	 * </p>
	 * 
	 * @param other 多组键值项拉平的列表
	 * @return 自身
	 * @throws RuntimeException
	 */
	@SuppressWarnings("unchecked")
	public MapBuilder<K, V> flatAddAll(Object... other) throws RuntimeException {
		if (!(other == null || other.length == 0)) {
			ArrayList<Entry<? extends K, ? extends V>> list = new ArrayList<>();
			for (int i = 0; i < other.length; i++) {
				K key = (K) other[i++];
				V val = (V) (i < other.length ? other[i] : null);
				list.add(createImmutableEntry(key, val));
			}
			addAll(list);
		}
		return this;
	}

	protected static <K, V> Entry<K, V> createImmutableEntry(K k, V v) {
		return ImmutablePair.of(k, v);
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1) {
		map.put(k1, v1);
		return this;
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @param k2 键2
	 * @param v2 值2
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1, K k2, V v2) {
		return add(k1, v1).add(k2, v2);
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @param k2 键2
	 * @param v2 值2
	 * @param k3 键3
	 * @param v3 值3
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1, K k2, V v2, K k3, V v3) {
		return add(k1, v1).add(k2, v2).add(k3, v3);
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @param k2 键2
	 * @param v2 值2
	 * @param k3 键3
	 * @param v3 值3
	 * @param k4 键4
	 * @param v4 值4
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
		return add(k1, v1).add(k2, v2).add(k3, v3).add(k4, v4);
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @param k2 键2
	 * @param v2 值2
	 * @param k3 键3
	 * @param v3 值3
	 * @param k4 键4
	 * @param v4 值4
	 * @param k5 键5
	 * @param v5 值5
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
		return add(k1, v1).add(k2, v2).add(k3, v3).add(k4, v4).add(k5, v5);
	}

	/**
	 * 内部哈希增加多组键值项
	 * 
	 * @param k1 键1
	 * @param v1 值1
	 * @param k2 键2
	 * @param v2 值2
	 * @param k3 键3
	 * @param v3 值3
	 * @param k4 键4
	 * @param v4 值4
	 * @param k5 键5
	 * @param v5 值5
	 * @param k6 键6
	 * @param v6 值6
	 * @return 自身
	 */
	public MapBuilder<K, V> add(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
		return add(k1, v1).add(k2, v2).add(k3, v3).add(k4, v4).add(k5, v5).add(k6, v6);
	}

}
